package com.zzl.finance.data.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.IoUtils;
import com.zzl.finance.data.constant.FileBucketTypeConstant;
import com.zzl.finance.data.constant.FileTypeConstant;
import com.zzl.finance.data.constant.StringConstant;
import com.zzl.finance.data.dto.BusinessInfoDto;
import com.zzl.finance.data.dto.MobileFile;
import com.zzl.finance.data.dto.MobileFileList;
import com.zzl.finance.data.dto.feign.FileInfo;
import com.zzl.finance.data.dto.feign.FileInfoPar;
import com.zzl.finance.data.feign.FileCenterFeign;
import com.zzl.finance.data.service.FileService;
import com.zzl.general.common.exception.SysException;
import com.zzl.general.common.utils.ResponseUtil;
import com.zzl.general.common.utils.Result;
import com.zzl.general.ocr.BdAiUntil;
import com.zzl.general.ocr.pojo.BusinessLicenseInfo;
import com.zzl.general.ocr.pojo.IDCardResult;
import com.zzl.general.qcc.QccUntil;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.zzl.finance.data.constant.StringConstant.FEIGN_EXCEPTION_CODE;
import static com.zzl.finance.data.constant.StringConstant.FEIGN_NORETURN_EXCEPTION_CODE;
import static com.zzl.general.common.utils.ResultCode.SUCCESS;

/**
 * @author gull
 * @date 2021-11-09 20:04:58
 */
@Service("fileService")
@Slf4j
@SuppressWarnings("unused")
public class FileServiceImpl implements FileService {
    @Autowired
    @SuppressWarnings("all")
    private FileCenterFeign fileCenterFeign;
    @Autowired
    @SuppressWarnings("all")
    private RabbitTemplate rabbitTemplate;
    @Autowired
    @SuppressWarnings("all")
    private QccUntil qccUntil;
    @Autowired
    @SuppressWarnings("all")
    private BdAiUntil bdAiUntil;
    @Autowired
    private FileService fileService;

    /**
     * 上传文件
     *
     * @param file 文件流
     */
    @Override
    public BusinessInfoDto upLoadBusinessInfoFile(MultipartFile file, String type) throws SysException {
        BusinessInfoDto businessInfoDto = new BusinessInfoDto();
        BusinessLicenseInfo businessLicenseInfo;
        IDCardResult idCardResult;
        String msg = "图片识别异常";
        String fileBucket;
        //营业执照识别
        try {
            if (FileTypeConstant.IMAGE_TYPE_BUSINESS_LICENSE.getKey().equals(type)) {
                businessLicenseInfo = bdAiUntil.businessLicenseOcr(file.getInputStream());
                businessInfoDto.setBusinessLicenseInfo(businessLicenseInfo);
                if (null == businessLicenseInfo.getWordsResult()) {
                    msg = "营业执照上传不正确，无法识别";
                    throw new SysException(msg);
                }
                fileBucket = FileBucketTypeConstant.FILE_BUCKET_BUSINESS_LICENSE.getKey();
            } else if (FileTypeConstant.IMAGE_TYPE_FRONT_ID_CARD.getKey().equals(type)) {
                //身份证正面识别
                idCardResult = bdAiUntil.idCardOcr(file.getInputStream());
                businessInfoDto.setIdCardResult(idCardResult);
                if (null == idCardResult.getName()) {
                    msg = "身份证正面上传不正确，无法识别";
                    throw new SysException(msg);
                }
                fileBucket = FileBucketTypeConstant.FILE_BUCKET_ID_CARD.getKey();
            } else if (FileTypeConstant.IMAGE_TYPE_BACK_ID_CARD.getKey().equals(type)) {
                //身份证反面识别
                idCardResult = bdAiUntil.idCardOcr(file.getInputStream());
                businessInfoDto.setIdCardResult(idCardResult);
                if (null == idCardResult.getExpiryDate()) {
                    msg = "身份证背面上传不正确，无法识别";
                    throw new SysException(msg);
                }
                fileBucket = FileBucketTypeConstant.FILE_BUCKET_ID_CARD.getKey();
            } else if (FileTypeConstant.FILE_TYPE_AUTHORIZATION_LETTER.getKey().equals(type)) {
                fileBucket = FileBucketTypeConstant.FILE_TYPE_AUTHORIZATION_LETTER.getKey();
            } else {
                msg = "图片类型输入不正确";
                throw new SysException(msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException(msg);
        }
        //上传文件到文件中心
        String objId = upLoadFile(file, fileBucket);
        businessInfoDto.setObjId(objId);
        return businessInfoDto;
    }

    /**
     * 手机上传图片
     *
     * @param file     文件
     * @param socketId 唯一标识
     * @return 文件id
     */
    @Override
    public String upLoadFileByMobile(MultipartFile file, String socketId, String type) throws SysException {
        //上传图片
        String objId = fileService.upLoadFile(file, FileBucketTypeConstant.FILE_ORDINARY_FILE.getKey());
        BusinessInfoDto businessInfoDto = new BusinessInfoDto();
        businessInfoDto.setObjId(objId);
        businessInfoDto.setType(type);
        //发送消息到mq，用于和前端进行socket通信
        sendMsgToMq(socketId, "上传文件成功", businessInfoDto.getObjId(), businessInfoDto);
        return businessInfoDto.getObjId();
    }

    /**
     * 发送消息到mq，用于和前端进行socket通信
     *
     * @param userId 用户id
     * @param msg    发送的消息
     * @param objId  发送的唯一标识
     * @throws SysException 业务异常
     */
    public void sendMsgToMq(String userId, String msg, String objId, BusinessInfoDto businessInfoDto) throws
            SysException {
        log.info("发送rabbitMq消息到" + userId);
        com.zzl.general.common.feign.params.MessageParams messageParams = new com.zzl.general.common.feign.params.MessageParams();
        Map<String, Object> map = new HashMap<>(2);
        // 增加在消息里加当前时间
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = df.format(new Date());
        map.put("msg", msg + "\r\n" + time);
        map.put("objId", objId);
        map.put("businessInfoDto", businessInfoDto);
        messageParams.setContent(JSON.toJSONString(map));
        //需要socket推送
        messageParams.setIsNeedSend(1);
        messageParams.setCategory("0");
        List<String> receiverIdList = new ArrayList<>();
        receiverIdList.add(userId);
        messageParams.setReceiverId(String.join(",", receiverIdList));
        //暂时写死 todo
        rabbitTemplate.convertAndSend("diExchange1", "d1", JSON.toJSONString(messageParams));
//        rabbitTemplate.convertAndSend(StringConstant.SUPPLIER_MQ_YYZZ, "d1", JSON.toJSONString(messageParams));
    }

    /**
     * 上传文件
     *
     * @param file   文件对象
     * @param bucket 文件桶
     * @return 文件id
     * @throws SysException 当调用feign时，无返回值或返回失败会抛出这个异常
     */
    @Override
    public String upLoadFile(MultipartFile file, String bucket) throws SysException {
        //上传文件到文件中心
        Result result = fileCenterFeign.uploadFileMongo(file, bucket);
        if (result == null) {
            throw new SysException(FEIGN_NORETURN_EXCEPTION_CODE, "上传失败！");
        }
        if (SUCCESS.getCode() == result.getCode()) {
            @SuppressWarnings({"rawtypes"})
            Map map = (Map) result.getResult().get(StringConstant.FILE_INFO);
            return (String) map.get(StringConstant.OBJ_ID);
        } else {
            throw new SysException(FEIGN_EXCEPTION_CODE, result.getMsg());
        }
    }

    /**
     * 下载文件
     *
     * @param response 响应对象
     * @param bucket   桶
     * @param objId    文件对象id
     * @param fileName 文件名称
     */
    @Override
    public void downloadFile(HttpServletResponse response, String bucket, String objId, String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            FileInfoPar fileInfoPar = new FileInfoPar();
            fileInfoPar.setBucket(bucket);
            fileInfoPar.setIds(Collections.singletonList(objId));
            Result fileFeignResult = fileCenterFeign.getFileNameByIds(fileInfoPar);
            if (SUCCESS.getCode() != fileFeignResult.getCode()) {
                ResponseUtil.out(response, Result.error("文件服务异常！"));
            }
            Object fileListObj = fileFeignResult.getResult().get("list");
            if (null == fileListObj) {
                ResponseUtil.out(response, Result.error("文件服务异常！"));
            }
            List<FileInfo> fileInfoList = JSON.parseArray(JSON.toJSONString(fileListObj), FileInfo.class);
            if (!CollectionUtils.isEmpty(fileInfoList)) {
                fileName = fileInfoList.get(0).getFileName();
            }
        }
        Response resp = fileCenterFeign.downloadFileMongoAllowAuth(objId, bucket);
        response.setCharacterEncoding("UTF-8");
        // 2.设置文件头：最后一个参数是设置下载文件名
        response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(), StandardCharsets.ISO_8859_1));
        try {
            IoUtils.copy(resp.body().asInputStream(), response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            ResponseUtil.out(response, Result.error(e.getMessage()));
        }
    }

    /**
     * 手机提交多个文件
     *
     * @param fileList 文件参数
     */
    @Override
    public void submitFileByMobile(MobileFileList fileList) throws SysException {
        String socketId = fileList.getSocketId();
        List<MobileFile> list = fileList.getList();
        for (MobileFile mobileFile : list) {
            BusinessInfoDto businessInfoDto = new BusinessInfoDto();
            businessInfoDto.setObjId(mobileFile.getObjId());
            businessInfoDto.setType(mobileFile.getType());
            //发送消息到mq，用于和前端进行socket通信
            sendMsgToMq(socketId, "上传文件成功", mobileFile.getObjId(), businessInfoDto);
        }
    }
}